//
//  VideoPlayer.swift
//  WatermarkCamera
//
//  Created by 赵新 on 6/7/2024.
//

import UIKit
import AxcBedrock
import AVFoundation

// MARK: - [Player.ObserverKeyPaths]

extension Player {
    /// 监听键值管理
    enum ObserverKeyPaths: String, CaseIterable {
        case status

        struct Info {
            var options: NSKeyValueObservingOptions = []
            var context: UnsafeMutableRawPointer?
        }

        var info: Info {
            switch self {
            case .status: return .init(options: .new, context: nil)
            }
        }
    }
}

// MARK: - [Player]

 class Player: AVPlayer {
    // Lifecycle

     override init(playerItem item: AVPlayerItem?) {
        super.init(playerItem: item)
        config()
    }

     override init() {
        super.init()
        config()
    }

    // Open

    /// 代理
     weak var delegate: PlayerDelegate?

    /// 准备完成后播放
     var isReadyToPlay: Bool = true

    /// 播放器状态
     var playerState: PlayerState = .none {
        didSet {
            delegate?.player(self, statusChange: playerState)
        }
    }

    /// 监听
     override func observeValue(forKeyPath keyPath: String?,
                                    of object: Any?,
                                    change: [NSKeyValueChangeKey: Any]?,
                                    context: UnsafeMutableRawPointer?) {
        guard let keyPath = keyPath,
              let caseKeyPath: ObserverKeyPaths = .init(rawValue: keyPath) else { return }
        switch caseKeyPath {
        // 播放状态
        case .status:
            guard let statusInt = change?[.newKey] as? Int,
                  let status: AVPlayer.Status = .init(rawValue: statusInt) else { return }
            playerStatusChange(status)
        }
    }

    /// 播放
     override func play() {
        playerState = .play
        delegate?.playerDidPlay(self)
        super.play()
    }

    /// 暂停
     override func pause() {
        playerState = .pause
        delegate?.playerDidPause(self)
        super.pause()
    }

    /// 切换播放任务
     override func replaceCurrentItem(with item: AVPlayerItem?) {
        super.pause()
        playerState = .loading
        delegate?.playerDidLoad(self)
        super.replaceCurrentItem(with: item)
        if let item = item {
            playProgressChange(item: item, time: .zero)
        }
    }

    // Internal

    /// 播放任务列表
    var taskItems: [AVPlayerItem] = []

    /// 播放模式
    var playMode: PlayMode = .single

    /// 从0开始
    var zeroTime: CMTime {
        return CMTime(seconds: 0, preferredTimescale: timeScale())
    }

    /// 配置
    func config() {
        // 注册所有监听
        ObserverKeyPaths.allCases.forEach { keyPath in
            self.addObserver(self,
                             forKeyPath: keyPath.rawValue,
                             options: keyPath.info.options,
                             context: keyPath.info.context)
        }
        // 播放完成通知
        NotificationCenter.default.addObserver(self,
                                               selector: #selector(self.playDidEnd(_:)),
                                               name: .AVPlayerItemDidPlayToEndTime,
                                               object: nil)

        // 播放进度更新
        addPeriodicTimeObserver(forInterval: .init(value: 1, timescale: 1),
                                queue: DispatchQueue.main) { [weak self] time in
            guard let weakSelf = self,
                  let item = weakSelf.currentItem else { return }
            weakSelf.playProgressChange(item: item, time: time)
        }

        automaticallyWaitsToMinimizeStalling = false
    }

    /// 播放状态改变
    func playerStatusChange(_ status: AVPlayer.Status) {
        switch status {
        case .readyToPlay:
            playerState = .readyToPlay
            if isReadyToPlay { // 设置了准备完成后自动播放
                play()
            }
            delegate?.playerDidReady(self)

        case .failed:
            delegate?.playerFailed(self)
            playerState = .loadFailed
        default: break
        }
    }

    /// 播放结束
    @objc
    func playDidEnd(_ notification: NSNotification) {
        guard let item = notification.object as? AVPlayerItem,
              item == currentItem else { return }
        playerState = .playEnd
        switch playMode {
        case .single:
            seek(to: zeroTime, toleranceBefore: .zero, toleranceAfter: .zero, completionHandler: { _ in
            })

        case .singleCycle:
            seek(to: zeroTime, toleranceBefore: .zero, toleranceAfter: .zero, completionHandler: { [weak self] _ in
                guard let weakSelf = self else { return }
                weakSelf.play()
            })

        case .listCycle:
            break

        case .random:
            break
        }
        delegate?.playerDidEnd(self)
    }

    /// 播放进度改变
    func playProgressChange(item: AVPlayerItem, time: CMTime) {
        let totalTime = item.duration.seconds
        guard !totalTime.isNaN,
              totalTime >= 0 else { return }
        let currentTime = time.seconds
        delegate?.player(self, progressChange: currentTime, totalSeconds: totalTime)
    }

    /// 移除所有监听
    func removeObserverKeyPaths() {
        ObserverKeyPaths.allCases.forEach { keyPath in
            self.removeObserver(self, forKeyPath: keyPath.rawValue)
        }
    }

    /// 移除所有监听
    func removeNotification() {
        NotificationCenter.default.removeObserver(self, name: .AVPlayerItemDidPlayToEndTime, object: nil)
    }
}

 extension Player {
    /// 播放模式
    enum PlayMode {
        /// 单个播放
        case single
        /// 单个循环
        case singleCycle
        /// 列表循环
        case listCycle
        /// 随机播放
        case random
    }

    /// 播放器状态
    enum PlayerState: Int {
        /// 无
        case none
        /// 加载数据中
        case loading
        /// 加载失败
        case loadFailed
        /// 加载完成，可以播放
        case readyToPlay
        /// 停止
        case stop
        /// 播放
        case play
        /// 暂停
        case pause
        /// 播放结束
        case playEnd

        struct Info {
            var description: String
        }

        var info: Info {
            switch self {
            case .none: return .init(description: "")
            case .loading: return .init(description: "加载中")
            case .loadFailed: return .init(description: "加载失败")
            case .readyToPlay: return .init(description: "准备播放")
            case .stop: return .init(description: "播放停止")
            case .play: return .init(description: "正在播放")
            case .pause: return .init(description: "播放暂停")
            case .playEnd: return .init(description: "播放完成")
            }
        }
    }
}

 extension Player {
    // MARK: 设置播放任务列表

    /// 添加一个url字符串
    func appendTaskWith(urlString: String) {
        appendTaskWith(url: .init(string: urlString))
    }

    /// 添加一个url
    func appendTaskWith(url: URL?) {
        guard let url = url else { return }
        appendTaskWith(item: .init(url: url))
    }

    /// 添加一个item
    func appendTaskWith(item: AVPlayerItem) {
        item.seek(to: zeroTime, toleranceBefore: .zero, toleranceAfter: .zero, completionHandler: { [weak self] _ in
            guard let weakSelf = self else { return }
            weakSelf.taskItems.append(item)
        })
    }

    /// 添加一个AVAsset
    func appendTaskWith(avAsset: AVAsset) {
        appendTaskWith(item: .init(asset: avAsset))
    }

    /// 添加一组urlString
    func appendTaskWith(urlStrings: [String]) {
        urlStrings.forEach { urlString in
            if let url = URL(string: urlString) {
                appendTaskWith(item: .init(url: url))
            }
        }
    }

    /// 添加一组url
    func appendTaskWith(urls: [URL]) {
        appendTaskWith(items: urls.map { AVPlayerItem(url: $0) })
    }

    /// 添加一组item
    func appendTaskWith(items: [AVPlayerItem]) {
        items.forEach { item in
            appendTaskWith(item: item)
        }
    }

    /// 添加一组AVAsset
    func appendTaskWith(avAssets: [AVAsset]) {
        var items: [AVPlayerItem] = []
        avAssets.forEach { avAssets in
            items.append(.init(asset: avAssets))
        }
        appendTaskWith(items: items)
    }

    /// 移除一个item
    func removeTaskWith(index: Int) {
        taskItems.remove(at: index)
    }

    /// 移除所有item
    func removeAllTask() {
        taskItems.removeAll()
        replaceCurrentItem(with: nil)
    }

    // MARK: 设置从第几个播放任务开始加载

    /// 加载第一个播放任务
    func loadFirstTask() {
        guard let taskItem = taskItems.first else { return }
        replaceCurrentItem(with: taskItem)
    }

    /// 加载最后一个播放任务
    func loadLastTask() {
        guard let taskItem = taskItems.last else { return }
        replaceCurrentItem(with: taskItem)
    }

    /// 加载第几个播放任务
    func loadTaskWith(index: Int) {
        guard let taskItem = taskItems.axc.object(at: index) else { return }
        replaceCurrentItem(with: taskItem)
    }

    // MARK: 播放相关设置

    /// 设置加载完成后是否自动播放
    func setReadyToPlay(_ isReadyToPlay: Bool) {
        self.isReadyToPlay = isReadyToPlay
    }

    /// 设置播放速度倍数
    func setPlayRate(_ rate: CGFloat) {
        self.rate = rate.axc.float
    }

    /// 设置播放模式
    func setPlayMode(_ playMode: PlayMode) {
        self.playMode = playMode
    }

    /// 播放或暂停
    func playOrPause() {
        if playerState == .play {
            pause()
        } else {
            play()
        }
    }

    /// 播放停止
    func stop() {
        playerState = .stop
        delegate?.playerDidStop(self)
        seek(to: zeroTime, toleranceBefore: .zero, toleranceAfter: .zero, completionHandler: { [weak self] _ in
            guard let weakSelf = self else { return }
            weakSelf.pause()
        })
    }

    func timeScale() -> Int32 {
        let timeScale = currentItem?.asset.duration.timescale ?? 30
        return timeScale
    }

    /// 销毁播放器
    func destroy() {
        // 移除计时器
//        removeTimeObserver(self)
        // 移除所有监听
        removeObserverKeyPaths()
        // 移除所有通知
        removeNotification()
    }
}

// MARK: - [PlayerDelegate]

 protocol PlayerDelegate: NSObjectProtocol {
    /// 播放器状态发生变化
    func player(_ player: Player, statusChange status: Player.PlayerState)

    /// 播放器开始加载
    func playerDidLoad(_ player: Player)

    /// 播放器出现错误
    func playerFailed(_ player: Player)

    /// 播放器准备完成
    func playerDidReady(_ player: Player)

    /// 播放器准备播放
    func playerDidPlay(_ player: Player)

    /// 播放器准备暂停
    func playerDidPause(_ player: Player)

    /// 播放器准备停止
    func playerDidStop(_ player: Player)

    /// 播放进度发生变化
    func player(_ player: Player, progressChange currentSeconds: Double, totalSeconds: Double)

    /// 播放器播放完成
    func playerDidEnd(_ player: Player)
}

 extension PlayerDelegate {
    /// 播放器状态发生变化
    func player(_ player: Player, statusChange status: Player.PlayerState) { }

    /// 播放器开始加载
    func playerDidLoad(_ player: Player) { }

    /// 播放器出现错误
    func playerFailed(_ player: Player) { }

    /// 播放器准备完成
    func playerDidReady(_ player: Player) { }

    /// 播放器准备播放
    func playerDidPlay(_ player: Player) { }

    /// 播放器准备暂停
    func playerDidPause(_ player: Player) { }

    /// 播放器准备停止
    func playerDidStop(_ player: Player) { }

    /// 播放进度发生变化
    func player(_ player: Player, progressChange currentSeconds: Double, totalSeconds: Double) { }

    /// 播放器播放完成
    func playerDidEnd(_ player: Player) { }
}
